package org.EasyDevelop.Builder;

import org.EasyDevelop.Bean.Constants;
import org.EasyDevelop.Bean.FieldInfo;
import org.EasyDevelop.Bean.TableInfo;
import org.EasyDevelop.Utils.PropertiesUtils;
import org.EasyDevelop.Utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//todo:try可以使用java8的新特性
public class TableBuilder {
    private static Connection connection = null;
    private static final Logger logger = LoggerFactory.getLogger(TableBuilder.class);

    private static String SQL_SHOW_TABLE_STATUS = "SHOW TABLE STATUS";

    private static String SQL_SHOW_TABLE_FIELDS = "SHOW FULL FIELDS FROM %s";

    private static String SQL_SHOW_INDEX = "SHOW INDEX FROM %s";


    static {
        String driverName = PropertiesUtils.getValue("db.driver.name");
        String url = PropertiesUtils.getValue("db.url");
        String username = PropertiesUtils.getValue("db.username");
        String password = PropertiesUtils.getValue("db.password");
        try{
            Class.forName(driverName);
            connection = DriverManager.getConnection(url,username,password);
        } catch (Exception e) {
            logger.error("数据库连接失败:{}",e);
        }
    }

    public static List<TableInfo> getTables(){
        PreparedStatement ps = null;
        ResultSet tableResult = null;
        List<TableInfo> tableInfos = new ArrayList<>();
        try {
            ps = connection.prepareStatement(SQL_SHOW_TABLE_STATUS);
            tableResult = ps.executeQuery();
            while (tableResult.next()){
                String tableName = tableResult.getString("name");
                String comment = tableResult.getString("comment");
                String beanName = tableName;
                //去前缀操作
                if(Boolean.valueOf(Constants.IGNORE_MAP.get("tablePrefix"))){
                    //当前缀相同的时候,去除相同 前缀_
                    if(tableName.substring(0,Constants.IGNORE_MAP.get("tablePrefixName").length()).equals(Constants.IGNORE_MAP.get("tablePrefixName"))){
                        beanName = tableName.substring(Constants.IGNORE_MAP.get("tablePrefixName").length() + 1);
                    }else{
                        //去除第一个_之前的前缀
                        beanName = tableName.substring(beanName.indexOf("_")+1);
                    }
                }
                beanName = StringUtils.processFiled(beanName,true);

                //填充tableInfo对象
                TableInfo tableInfo = new TableInfo();
                tableInfo.setTableName(tableName);
                tableInfo.setBeanName(beanName);
                tableInfo.setComment(comment);
                tableInfo.setBeanParamName(beanName + StringUtils.upperCaseFirstLetter(Constants.SUFFIX_MAP.get("queryParam")));
                tableInfo.setHaveDate(false);
                tableInfo.setHaveDateTime(false);
                tableInfo.setHaveBigDecimal(false);
                tableInfo.setHaveIgnoreField(false);
                tableInfo.setHaveAutoIncrement(false);

                readFieldInfo(tableInfo);//读取表字段

                getKeyIndexInfo(tableInfo);//读取索引
//                System.out.println(tableInfo);
                tableInfos.add(tableInfo);

//                logger.info("tableInfo:{}",tableInfo);
            }
        } catch (Exception e) {
            logger.error("读取表信息失败:{}",e);
        } finally {
            if(tableResult!=null) {
                try {
                    tableResult.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(ps!=null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(connection!=null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return tableInfos;
    }

    //读取字段类型
    private static void readFieldInfo(TableInfo tableInfo){
        PreparedStatement ps = null;
        ResultSet fieldResult = null;
        List<FieldInfo> fieldInfos = new ArrayList<>();

        try{
            ps = connection.prepareStatement(String.format(SQL_SHOW_TABLE_FIELDS,tableInfo.getTableName()));
            fieldResult = ps.executeQuery();
            while (fieldResult.next()){
                //获取属性
                String fieldName = fieldResult.getString("field");
                String type = fieldResult.getString("type");
                String extra = fieldResult.getString("extra");
                String comment = fieldResult.getString("comment");

                //去除()
                if(type.contains("(")){
                    type = type.substring(0,type.indexOf("("));
                }

                //bean属性
                String propertyName = StringUtils.processFiled(fieldName,false);

                //赋值
                FieldInfo fieldInfo = new FieldInfo();
                fieldInfo.setComment(comment);
                fieldInfo.setFieldName(fieldName);
                fieldInfo.setSqlType(type);
                fieldInfo.setIsAutoIncrement("".equals(extra)?false:true);
                fieldInfo.setPropertyName(propertyName);
                fieldInfo.setJavaType(processJavaType(type));
                if(ArrayUtils.contains(Constants.SQL_DATE_TYPES,type)){
                    tableInfo.setHaveDate(true);
                }
                if(ArrayUtils.contains(Constants.SQL_DATE_TIME_TYPES,type)){
                    tableInfo.setHaveDateTime(true);
                }
                if(ArrayUtils.contains(Constants.SQL_DECIMAL_TYPES,type)){
                    tableInfo.setHaveBigDecimal(true);
                }
                if(ArrayUtils.contains(Constants.IGNORE_MAP.get("beanToJsonFiled").split(","),fieldInfo.getFieldName())){
                    tableInfo.setHaveIgnoreField(true);
                }

                //TODO:构建特殊字段

                //加入到fieldInfos中
                fieldInfos.add(fieldInfo);

//                logger.info("field:{}",fieldInfo);

            }
            tableInfo.setFieldList(fieldInfos);
        }catch (Exception e){
            logger.error("读取表字段失败!{}",e);
        }finally {
            if(fieldResult!=null) {
                try {
                    fieldResult.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(ps!=null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }

    //获取数据库表的索引
    private static void getKeyIndexInfo(TableInfo tableInfo){
        PreparedStatement ps = null;
        ResultSet fieldResult = null;
        try{
            Map<String,FieldInfo> tempMap = new HashMap<>();
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                tempMap.put(fieldInfo.getFieldName(),fieldInfo);
            }
            ps = connection.prepareStatement(String.format(SQL_SHOW_INDEX,tableInfo.getTableName()));
            fieldResult = ps.executeQuery();
            while (fieldResult.next()){
                //获取属性
                String keyName = fieldResult.getString("key_name");
                Boolean nonUnique = fieldResult.getInt("non_unique") == 1;
                if (nonUnique) continue;
                String columnName = fieldResult.getString("column_name");
                List<FieldInfo> keyFieldList = tableInfo.getKeyIndexMap().get(keyName);
                if(null == keyFieldList){
                    keyFieldList = new ArrayList<>();
                    tableInfo.getKeyIndexMap().put(keyName,keyFieldList);
                }
                keyFieldList.add(tempMap.get(columnName));
            }
        }catch (Exception e){
            logger.error("读取索引失败!{}",e);
        }finally {
            if(fieldResult!=null) {
                try {
                    fieldResult.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(ps!=null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }



    //数据库类型转换成Java类型
    //TODO:策略模式
    private static String processJavaType(String type){
        if(ArrayUtils.contains(Constants.SQL_DECIMAL_TYPES,type))
            return "BigDecimal";
        else if (ArrayUtils.contains(Constants.SQL_DATE_TYPES,type) || ArrayUtils.contains(Constants.SQL_DATE_TIME_TYPES,type))
            return "Date";
        else if(ArrayUtils.contains(Constants.SQL_STRING_TYPES,type))
            return "String";
        else if (ArrayUtils.contains(Constants.SQL_LONG_TYPES,type))
            return "Long";
        else if (ArrayUtils.contains(Constants.SQL_INTEGER_TYPES,type))
            return "Integer";
        else throw new RuntimeException("无法识别的类型:" + type);

    }

    public static void main(String[] args) {
        System.out.println(StringUtils.processFiled("user_info", true));
    }
}
